Scripts {pliman} 67ª RBRAS e 20º SEAGRO

1 Pacotes

library(pliman)
library(tidyverse)
setwd("D:/Desktop/UFSC/cursos/pliman67rbras")
set_wd_here()
# set_pliman_viewer("mapview")

2 Importação e manipulação

2.1 Importação

leaves <- image_import("leaves.jpg", plot = TRUE)

2.2 Resolução

dpi(leaves, viewer = "mapview")

2.3 Cortar, girar e redimensionar

crop <- image_autocrop(leaves, plot = TRUE)

# crop <- image_crop(leaves, viewer = "mapview")

crop <- image_crop(leaves,
                   width = 137:912, 
                   height = 59:739)

3 Segmentação

# Índices para segmentação
pliman_indexes()
##  [1] "R"     "G"     "B"     "NR"    "NG"    "NB"    "GB"    "RB"    "GR"   
## [10] "BI"    "BIM"   "SCI"   "GLI"   "HI"    "NGRDI" "NDGBI" "NDRBI" "I"    
## [19] "S"     "VARI"  "HUE"   "HUE2"  "BGI"   "L"     "GRAY"  "GLAI"  "CI"   
## [28] "SHP"   "RI"    "G-B"   "G-R"   "R-G"   "R-B"   "B-R"   "B-G"   "DGCI" 
## [37] "GRAY2" "L*"    "a"     "b*"    "L*-a"  "L*-b"  "b*-a"
index <- image_index(leaves, index = c("R", "G", "B", "B-R"))

plot(index, type = "density")

# Imagem binária
binary <- image_binary(leaves, index = "B-R")

binary <- 
  image_binary(leaves,
               index = "B-R",
               invert = TRUE)

binary <- 
  image_binary(leaves, 
               index = "B-R",
               fill_hull = TRUE)

binary <- 
  image_binary(leaves, 
               index = "B-R",
               filter = 5,
               fill_hull = TRUE)

# Segmentação
seg <- image_segment(leaves,
                     # threshold = 0.1,
                     # threshold = "aa",
                     index = "B-R")

4 Análise de objetos

4.1 Imagem única

grains <- image_import("grains.jpg", plot = TRUE)

# Analisar os objetos
res <- analyze_objects(grains, index = "GRAY")

res$statistics
# Algumas funcionalidades
res <- 
  analyze_objects(grains, 
                  index = "GRAY",
                  lower_noise = 0.4,      # remove ruídos maiores
                  show_contour = FALSE,
                  marker = "point")

plot(res)

res <- 
  analyze_objects(grains, 
                  index = "GRAY",
                  topn_upper = 10,        # Somente os 10 maiores grãos
                  show_contour = FALSE,
                  marker = "point")

4.2 Processamento em lote com correção (referência)

4.2.1 Pelo tamanho da referência

# Analisar os objetos
res <- 
  analyze_objects(pattern = "P",
                  dir_original = "flax_grain",    # subpasta com as imagens originais
                  dir_processed = "proc",         # subpasta com as imagens processadas
                  reference = TRUE,               # indica que há uma referência
                  reference_larger = TRUE,        # indica que a referência é o maior objeto 
                  reference_area = 6,             # a referência tem 6 cm2
                  index = "GRAY",
                  show_contour = FALSE,
                  marker = "point",
                  plot = FALSE,
                  save_image = TRUE)
## Processing image P01 |=======                                    | 17% 00:00:00 
## Processing image P02 |==============                             | 33% 00:00:04 
## Processing image P03 |======================                     | 50% 00:00:12 
## Processing image P04 |=============================              | 67% 00:00:19 
## Processing image P05 |====================================       | 83% 00:00:23 
## Processing image P06 |===========================================| 100% 00:00:27 
## --------------------------------------------
##  Image Objects
##    P01     277
##    P02      91
##    P03     179
##    P04     112
##    P05      22
##    P06      78
## --------------------------------------------
hist(res$results$length)

4.2.2 Pela cor da referência

flax <- image_import("flax_af/A2_32_3.jpg", plot = TRUE)

# Índice para segmentar a referência e folhas do fundo
image_segment_iter(flax, 
                   index = c("R/(G/B)", "B-R"),
                   ncol = 3)
##      image pixels   percent
## 1 original 806490 100.00000
## 2     seg1 129657  16.07670
## 3     seg2  38517  29.70684

# Note que agora o processamento é realizado de forma paralela
res <-
  analyze_objects(pattern = "A",
                  dir_original = "flax_af",
                  reference = TRUE,
                  reference_area = 20,
                  watershed = FALSE,
                  filter = 2,
                  plot = FALSE,
                  parallel = TRUE)
## --------------------------------------------
##      Image Objects
##    A1_28_1      18
##    A1_28_2      28
##    A1_28_3      28
##   A10_90_1     149
##   A10_90_2     116
##   A10_90_3      77
##   A11_98_1     132
##   A11_98_2     151
##   A11_98_3     119
##  A12_105_1     110
##  A12_105_2     127
##  A12_105_3     154
##    A2_32_1      23
##    A2_32_2      25
##    A2_32_3      31
##    A3_42_1      39
##    A3_42_2      47
##    A3_42_3      52
##    A4_46_1      58
##    A4_46_2      38
##    A4_46_3      56
##    A5_55_1      53
##    A5_55_2      74
##    A5_55_3      61
##    A6_63_1      68
##    A6_63_2     105
##    A6_63_3      83
##    A7_70_1      98
##    A7_70_2     111
##    A7_70_3     112
##    A8_76_1     113
##    A8_76_2     118
##    A8_76_3     114
##    A9_83_1     120
##    A9_83_2      89
##    A9_83_3     101
## --------------------------------------------
merged <- get_measures(res)


# Organizar os dados para ajuste do modelo Logístico
df_plot <- 
  merged$summary |> 
  separate_col(img, 
               into = c("avaliacao", "das", "bloco")) |> 
  mutate(das = as.numeric(das))

formula <- y ~ b1/(1 + exp(b2 - b3 * x))

ggplot(df_plot, aes(das, area_sum)) + 
  geom_smooth(method = "nls",
              method.args = list(formula = formula,
                                 start = c(b1 = 248,
                                           b2 = 6,
                                           b3 = 0.07)),
              se = FALSE,
              color = "red") +
  stat_summary(fun.data = mean_se,
               geom = "errorbar",
               width = 0.5) +
  stat_summary(fun = mean,
               geom = "point",
               col = "blue",
               size = 3) +
  scale_x_continuous(breaks = unique(df_plot$das)) +
  scale_y_continuous(breaks = seq(0, 150, by = 25)) +
  labs(x = "Dias após a semeadura",
       y = expression(Área~foliar~média~(cm^2~planta^{-1}))) +
  theme_bw(base_size = 16) +
  theme(panel.grid = element_blank()) 

5 Ortomosaicos

Imagens disponibilizadas por Filipe Matias, no github do FIELDimageR

5.1 Cobertura vegetal (canopy)

# imagem
img <- 
  image_import("potatoes.tif", path = "orthomosaic") |> 
  image_horizontal()

plot(img)

# preparar a imagem
# Somente iterativo
# prep <- image_prepare_mv(img)
prep <- 
  img |> 
  image_rotate(-2.076, plot = FALSE) |> 
  image_crop(width = 194:1075,
             height = 143:379,
             plot = TRUE)

# índice para segmentação
image_index(prep, index =  "HUE")

res <- 
  analyze_objects_shp(prep,
                      nrow = 16,
                      ncol = 9,
                      index = "HUE",
                      object_index = c("NGRDI", "DGCI"))

# cobertura de solo
plot_index_shp(res)

# resumir as informações
results <- get_measures(res)

5.2 Índices de vegetação

# Nível de parcela
plot_index_shp(res, attribute = "NGRDI")

# Nível de pixel
plot_index(object = res, index = "DGCI")

# plot_index(object = res, index = "DGCI", viewer = "map")

# resumir as informações
results <- get_measures(res)

5.3 Stand de plantas

# imagem
stand <- image_import("stand.jpg", path = "orthomosaic", plot = TRUE)

# índice para segmentação
image_segment(stand, "HUE")

image_segment(stand, "NGRDI")

image_segment(stand, "NGRDI", invert = TRUE)

res <- 
  analyze_objects_shp(stand,
                      index = "NGRDI",
                      invert = TRUE,
                      nrow = 7,
                      ncol = 1)

par(mfrow = c(1, 2))
# cobertura de solo
plot_index_shp(res)

# mapeamento das plantas (distâncias e CV(%))
object_mark(res)
mapped <-  object_map(res)

# coeficiente de variação dentro da linha
barplot(mapped$cvs)

par(mfrow = c(1, 1))

6 Fitopatometria

6.1 Iterativa

folha <- image_pliman("sev_leaf.jpg", plot = TRUE)

# measure_disease_iter(folha, viewer = "mapview")

6.2 Usando paletas

folha <- image_import("soybean_rust/soy_1.jpg", plot = TRUE)

pals <- image_import(pattern = "soja_",
                     path = "soybean_rust",
                     plot = TRUE,
                     ncol = 3)

sev <- 
  measure_disease(folha,
                  img_healthy = pals$soja_h.png,     # paleta para folha sadia
                  img_symptoms = pals$soja_s.png,    # paleta para folha doente
                  img_background = pals$soja_b.png)  # paleta para fundo

sev$severity

6.3 Usando índices de imagem

# Índice para segmentar a folha do fundo, depois a doença da folha
image_segment_iter(folha, 
                   index = c("B", "NGRDI"),
                   ncol = 3)
##      image  pixels   percent
## 1 original 4813707 100.00000
## 2     seg1 2781900  57.79122
## 3     seg2  384237  13.81203

# IMPORTANTE: theshold vai alterar a severidade
sev2 <- 
  measure_disease(folha,
                  index_lb = "B",            # índice para segmentar a folha do fundo
                  index_dh = "NGRDI",        # índice para segmentar folha doente e sadia
                  threshold = c("Otsu", 0))  # threshold para os dois índices, respectivamente

sev2$severity
# em lote (utilizando as paletas)
sev3 <- 
  measure_disease(pattern = "soy_",
                  dir_original = "soybean_rust",    # pasta com as imagens originais
                  dir_processed = "proc_rust",      # pasta com as imagens processadas
                  save_image = TRUE,
                  plot = FALSE,
                  img_healthy = pals$soja_h.png,
                  img_symptoms = pals$soja_s.png,
                  img_background = pals$soja_b.png,
                  parallel = TRUE)
# standard area diagrams
sad(sev3, n = 6)
sev4 <- 
  measure_disease(pattern = "soy_",
                  dir_original = "soybean_rust",
                  plot = FALSE,
                  index_lb = "B",
                  index_dh = "NGRDI",
                  threshold = c("Otsu", 0),
                  parallel = TRUE)

plot(sev3$severity$symptomatic, sev4$severity$symptomatic)

6.4 Em grids

folha_grid <- image_import("disease_shp.jpg", plot = TRUE)
sev5 <- 
  measure_disease_shp(folha_grid,
                      index_lb = "HUE2",
                      index_dh = "NGRDI",
                      threshold = c("Otsu", 0),
                      filter = 10,
                      ncol = 3,
                      nrow = 3,
                      plot = FALSE)
plot(folha_grid)
plot(sev5$shapefiles)
plot_measures(sev5, "symptomatic")


  1. Universidade Federal de Santa Catarina, https://olivoto.netlify.app/↩︎

LS0tDQp0aXRsZTogIlNjcmlwdHMge3BsaW1hbn0gNjfCqiBSQlJBUyBlIDIwwrogU0VBR1JPIg0KYXV0aG9yOg0KICAtIFRpYWdvIE9saXZvdG9eW1VuaXZlcnNpZGFkZSBGZWRlcmFsIGRlIFNhbnRhIENhdGFyaW5hLCBodHRwczovL29saXZvdG8ubmV0bGlmeS5hcHAvXQ0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgbGlnaHRib3g6IHRydWUNCiAgICBnYWxsZXJ5OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlDQoNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBlcnJvciA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQ0KDQpgYGANCg0KWyFbXShsb2dvLnBuZyldKGh0dHBzOi8vNjdyYnJhczIwc2VhZ3JvLmNvbS5ici8pDQoNCiMgUGFjb3Rlcw0KDQpgYGB7cn0NCmxpYnJhcnkocGxpbWFuKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpzZXR3ZCgiRDovRGVza3RvcC9VRlNDL2N1cnNvcy9wbGltYW42N3JicmFzIikNCnNldF93ZF9oZXJlKCkNCiMgc2V0X3BsaW1hbl92aWV3ZXIoIm1hcHZpZXciKQ0KDQpgYGANCg0KIyBJbXBvcnRhw6fDo28gZSBtYW5pcHVsYcOnw6NvDQojIyBJbXBvcnRhw6fDo28NCmBgYHtyfQ0KbGVhdmVzIDwtIGltYWdlX2ltcG9ydCgibGVhdmVzLmpwZyIsIHBsb3QgPSBUUlVFKQ0KDQpgYGANCg0KIyMgUmVzb2x1w6fDo28NCmBgYHtyIGV2YWw9RkFMU0V9DQpkcGkobGVhdmVzLCB2aWV3ZXIgPSAibWFwdmlldyIpDQpgYGANCg0KDQojIyBDb3J0YXIsIGdpcmFyIGUgcmVkaW1lbnNpb25hcg0KYGBge3J9DQpjcm9wIDwtIGltYWdlX2F1dG9jcm9wKGxlYXZlcywgcGxvdCA9IFRSVUUpDQojIGNyb3AgPC0gaW1hZ2VfY3JvcChsZWF2ZXMsIHZpZXdlciA9ICJtYXB2aWV3IikNCg0KY3JvcCA8LSBpbWFnZV9jcm9wKGxlYXZlcywNCiAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDEzNzo5MTIsIA0KICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDU5OjczOSkNCmBgYA0KDQoNCiMgU2VnbWVudGHDp8Ojbw0KYGBge3J9DQojIMONbmRpY2VzIHBhcmEgc2VnbWVudGHDp8Ojbw0KcGxpbWFuX2luZGV4ZXMoKQ0KaW5kZXggPC0gaW1hZ2VfaW5kZXgobGVhdmVzLCBpbmRleCA9IGMoIlIiLCAiRyIsICJCIiwgIkItUiIpKQ0KcGxvdChpbmRleCwgdHlwZSA9ICJkZW5zaXR5IikNCg0KIyBJbWFnZW0gYmluw6FyaWENCmJpbmFyeSA8LSBpbWFnZV9iaW5hcnkobGVhdmVzLCBpbmRleCA9ICJCLVIiKQ0KYmluYXJ5IDwtIA0KICBpbWFnZV9iaW5hcnkobGVhdmVzLA0KICAgICAgICAgICAgICAgaW5kZXggPSAiQi1SIiwNCiAgICAgICAgICAgICAgIGludmVydCA9IFRSVUUpDQpiaW5hcnkgPC0gDQogIGltYWdlX2JpbmFyeShsZWF2ZXMsIA0KICAgICAgICAgICAgICAgaW5kZXggPSAiQi1SIiwNCiAgICAgICAgICAgICAgIGZpbGxfaHVsbCA9IFRSVUUpDQpiaW5hcnkgPC0gDQogIGltYWdlX2JpbmFyeShsZWF2ZXMsIA0KICAgICAgICAgICAgICAgaW5kZXggPSAiQi1SIiwNCiAgICAgICAgICAgICAgIGZpbHRlciA9IDUsDQogICAgICAgICAgICAgICBmaWxsX2h1bGwgPSBUUlVFKQ0KDQojIFNlZ21lbnRhw6fDo28NCnNlZyA8LSBpbWFnZV9zZWdtZW50KGxlYXZlcywNCiAgICAgICAgICAgICAgICAgICAgICMgdGhyZXNob2xkID0gMC4xLA0KICAgICAgICAgICAgICAgICAgICAgIyB0aHJlc2hvbGQgPSAiYWEiLA0KICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSAiQi1SIikNCmBgYA0KDQoNCg0KIyBBbsOhbGlzZSBkZSBvYmpldG9zDQojIyBJbWFnZW0gw7puaWNhDQpgYGB7cn0NCmdyYWlucyA8LSBpbWFnZV9pbXBvcnQoImdyYWlucy5qcGciLCBwbG90ID0gVFJVRSkNCg0KIyBBbmFsaXNhciBvcyBvYmpldG9zDQpyZXMgPC0gYW5hbHl6ZV9vYmplY3RzKGdyYWlucywgaW5kZXggPSAiR1JBWSIpDQpyZXMkc3RhdGlzdGljcw0KDQojIEFsZ3VtYXMgZnVuY2lvbmFsaWRhZGVzDQpyZXMgPC0gDQogIGFuYWx5emVfb2JqZWN0cyhncmFpbnMsIA0KICAgICAgICAgICAgICAgICAgaW5kZXggPSAiR1JBWSIsDQogICAgICAgICAgICAgICAgICBsb3dlcl9ub2lzZSA9IDAuNCwgICAgICAjIHJlbW92ZSBydcOtZG9zIG1haW9yZXMNCiAgICAgICAgICAgICAgICAgIHNob3dfY29udG91ciA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgbWFya2VyID0gInBvaW50IikNCnBsb3QocmVzKQ0KDQpyZXMgPC0gDQogIGFuYWx5emVfb2JqZWN0cyhncmFpbnMsIA0KICAgICAgICAgICAgICAgICAgaW5kZXggPSAiR1JBWSIsDQogICAgICAgICAgICAgICAgICB0b3BuX3VwcGVyID0gMTAsICAgICAgICAjIFNvbWVudGUgb3MgMTAgbWFpb3JlcyBncsOjb3MNCiAgICAgICAgICAgICAgICAgIHNob3dfY29udG91ciA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgbWFya2VyID0gInBvaW50IikNCg0KYGBgDQoNCg0KIyMgUHJvY2Vzc2FtZW50byBlbSBsb3RlIGNvbSBjb3JyZcOnw6NvIChyZWZlcsOqbmNpYSkNCiMjIyBQZWxvIHRhbWFuaG8gZGEgcmVmZXLDqm5jaWENCmBgYHtyfQ0KIyBBbmFsaXNhciBvcyBvYmpldG9zDQpyZXMgPC0gDQogIGFuYWx5emVfb2JqZWN0cyhwYXR0ZXJuID0gIlAiLA0KICAgICAgICAgICAgICAgICAgZGlyX29yaWdpbmFsID0gImZsYXhfZ3JhaW4iLCAgICAjIHN1YnBhc3RhIGNvbSBhcyBpbWFnZW5zIG9yaWdpbmFpcw0KICAgICAgICAgICAgICAgICAgZGlyX3Byb2Nlc3NlZCA9ICJwcm9jIiwgICAgICAgICAjIHN1YnBhc3RhIGNvbSBhcyBpbWFnZW5zIHByb2Nlc3NhZGFzDQogICAgICAgICAgICAgICAgICByZWZlcmVuY2UgPSBUUlVFLCAgICAgICAgICAgICAgICMgaW5kaWNhIHF1ZSBow6EgdW1hIHJlZmVyw6puY2lhDQogICAgICAgICAgICAgICAgICByZWZlcmVuY2VfbGFyZ2VyID0gVFJVRSwgICAgICAgICMgaW5kaWNhIHF1ZSBhIHJlZmVyw6puY2lhIMOpIG8gbWFpb3Igb2JqZXRvIA0KICAgICAgICAgICAgICAgICAgcmVmZXJlbmNlX2FyZWEgPSA2LCAgICAgICAgICAgICAjIGEgcmVmZXLDqm5jaWEgdGVtIDYgY20yDQogICAgICAgICAgICAgICAgICBpbmRleCA9ICJHUkFZIiwNCiAgICAgICAgICAgICAgICAgIHNob3dfY29udG91ciA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgbWFya2VyID0gInBvaW50IiwNCiAgICAgICAgICAgICAgICAgIHBsb3QgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgIHNhdmVfaW1hZ2UgPSBUUlVFKQ0KDQpoaXN0KHJlcyRyZXN1bHRzJGxlbmd0aCkNCg0KYGBgDQoNCg0KIyMjIFBlbGEgY29yIGRhIHJlZmVyw6puY2lhDQpgYGB7cn0NCiN8IG91dC13aWR0aDogIjEwMCUiDQpmbGF4IDwtIGltYWdlX2ltcG9ydCgiZmxheF9hZi9BMl8zMl8zLmpwZyIsIHBsb3QgPSBUUlVFKQ0KDQojIMONbmRpY2UgcGFyYSBzZWdtZW50YXIgYSByZWZlcsOqbmNpYSBlIGZvbGhhcyBkbyBmdW5kbw0KaW1hZ2Vfc2VnbWVudF9pdGVyKGZsYXgsIA0KICAgICAgICAgICAgICAgICAgIGluZGV4ID0gYygiUi8oRy9CKSIsICJCLVIiKSwNCiAgICAgICAgICAgICAgICAgICBuY29sID0gMykNCg0KDQojIE5vdGUgcXVlIGFnb3JhIG8gcHJvY2Vzc2FtZW50byDDqSByZWFsaXphZG8gZGUgZm9ybWEgcGFyYWxlbGENCnJlcyA8LQ0KICBhbmFseXplX29iamVjdHMocGF0dGVybiA9ICJBIiwNCiAgICAgICAgICAgICAgICAgIGRpcl9vcmlnaW5hbCA9ICJmbGF4X2FmIiwNCiAgICAgICAgICAgICAgICAgIHJlZmVyZW5jZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICByZWZlcmVuY2VfYXJlYSA9IDIwLA0KICAgICAgICAgICAgICAgICAgd2F0ZXJzaGVkID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBmaWx0ZXIgPSAyLA0KICAgICAgICAgICAgICAgICAgcGxvdCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUUlVFKQ0KDQptZXJnZWQgPC0gZ2V0X21lYXN1cmVzKHJlcykNCg0KDQojIE9yZ2FuaXphciBvcyBkYWRvcyBwYXJhIGFqdXN0ZSBkbyBtb2RlbG8gTG9nw61zdGljbw0KZGZfcGxvdCA8LSANCiAgbWVyZ2VkJHN1bW1hcnkgfD4gDQogIHNlcGFyYXRlX2NvbChpbWcsIA0KICAgICAgICAgICAgICAgaW50byA9IGMoImF2YWxpYWNhbyIsICJkYXMiLCAiYmxvY28iKSkgfD4gDQogIG11dGF0ZShkYXMgPSBhcy5udW1lcmljKGRhcykpDQoNCmZvcm11bGEgPC0geSB+IGIxLygxICsgZXhwKGIyIC0gYjMgKiB4KSkNCg0KZ2dwbG90KGRmX3Bsb3QsIGFlcyhkYXMsIGFyZWFfc3VtKSkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gIm5scyIsDQogICAgICAgICAgICAgIG1ldGhvZC5hcmdzID0gbGlzdChmb3JtdWxhID0gZm9ybXVsYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYyhiMSA9IDI0OCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiMiA9IDYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjMgPSAwLjA3KSksDQogICAgICAgICAgICAgIHNlID0gRkFMU0UsDQogICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwNCiAgICAgICAgICAgICAgIGdlb20gPSAiZXJyb3JiYXIiLA0KICAgICAgICAgICAgICAgd2lkdGggPSAwLjUpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sDQogICAgICAgICAgICAgICBnZW9tID0gInBvaW50IiwNCiAgICAgICAgICAgICAgIGNvbCA9ICJibHVlIiwNCiAgICAgICAgICAgICAgIHNpemUgPSAzKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSB1bmlxdWUoZGZfcGxvdCRkYXMpKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTUwLCBieSA9IDI1KSkgKw0KICBsYWJzKHggPSAiRGlhcyBhcMOzcyBhIHNlbWVhZHVyYSIsDQogICAgICAgeSA9IGV4cHJlc3Npb24ow4FyZWF+Zm9saWFyfm3DqWRpYX4oY21eMn5wbGFudGFeey0xfSkpKSArDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE2KSArDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpIA0KDQpgYGANCg0KDQoNCiMgT3J0b21vc2FpY29zDQpJbWFnZW5zIGRpc3BvbmliaWxpemFkYXMgcG9yIEZpbGlwZSBNYXRpYXMsIG5vIGdpdGh1YiBkbyBbRklFTERpbWFnZVJdKFJodHRwczovL2dpdGh1Yi5jb20vT3BlbkRyb25lTWFwL0ZJRUxEaW1hZ2VSKQ0KDQojIyBDb2JlcnR1cmEgdmVnZXRhbCAoY2Fub3B5KQ0KDQpgYGB7cn0NCiMgaW1hZ2VtDQppbWcgPC0gDQogIGltYWdlX2ltcG9ydCgicG90YXRvZXMudGlmIiwgcGF0aCA9ICJvcnRob21vc2FpYyIpIHw+IA0KICBpbWFnZV9ob3Jpem9udGFsKCkNCg0KcGxvdChpbWcpDQoNCiMgcHJlcGFyYXIgYSBpbWFnZW0NCiMgU29tZW50ZSBpdGVyYXRpdm8NCiMgcHJlcCA8LSBpbWFnZV9wcmVwYXJlX212KGltZykNCnByZXAgPC0gDQogIGltZyB8PiANCiAgaW1hZ2Vfcm90YXRlKC0yLjA3NiwgcGxvdCA9IEZBTFNFKSB8PiANCiAgaW1hZ2VfY3JvcCh3aWR0aCA9IDE5NDoxMDc1LA0KICAgICAgICAgICAgIGhlaWdodCA9IDE0MzozNzksDQogICAgICAgICAgICAgcGxvdCA9IFRSVUUpDQoNCg0KIyDDrW5kaWNlIHBhcmEgc2VnbWVudGHDp8Ojbw0KaW1hZ2VfaW5kZXgocHJlcCwgaW5kZXggPSAgIkhVRSIpDQoNCg0KcmVzIDwtIA0KICBhbmFseXplX29iamVjdHNfc2hwKHByZXAsDQogICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDE2LA0KICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgIGluZGV4ID0gIkhVRSIsDQogICAgICAgICAgICAgICAgICAgICAgb2JqZWN0X2luZGV4ID0gYygiTkdSREkiLCAiREdDSSIpKQ0KDQojIGNvYmVydHVyYSBkZSBzb2xvDQpwbG90X2luZGV4X3NocChyZXMpDQoNCiMgcmVzdW1pciBhcyBpbmZvcm1hw6fDtWVzDQpyZXN1bHRzIDwtIGdldF9tZWFzdXJlcyhyZXMpDQpgYGANCg0KIyMgw41uZGljZXMgZGUgdmVnZXRhw6fDo28NCg0KYGBge3J9DQojIE7DrXZlbCBkZSBwYXJjZWxhDQpwbG90X2luZGV4X3NocChyZXMsIGF0dHJpYnV0ZSA9ICJOR1JESSIpDQoNCiMgTsOtdmVsIGRlIHBpeGVsDQpwbG90X2luZGV4KG9iamVjdCA9IHJlcywgaW5kZXggPSAiREdDSSIpDQojIHBsb3RfaW5kZXgob2JqZWN0ID0gcmVzLCBpbmRleCA9ICJER0NJIiwgdmlld2VyID0gIm1hcCIpDQoNCiMgcmVzdW1pciBhcyBpbmZvcm1hw6fDtWVzDQpyZXN1bHRzIDwtIGdldF9tZWFzdXJlcyhyZXMpDQpgYGANCg0KIyMgU3RhbmQgZGUgcGxhbnRhcw0KDQpgYGB7cn0NCiMgaW1hZ2VtDQpzdGFuZCA8LSBpbWFnZV9pbXBvcnQoInN0YW5kLmpwZyIsIHBhdGggPSAib3J0aG9tb3NhaWMiLCBwbG90ID0gVFJVRSkNCg0KDQojIMOtbmRpY2UgcGFyYSBzZWdtZW50YcOnw6NvDQppbWFnZV9zZWdtZW50KHN0YW5kLCAiSFVFIikNCmltYWdlX3NlZ21lbnQoc3RhbmQsICJOR1JESSIpDQppbWFnZV9zZWdtZW50KHN0YW5kLCAiTkdSREkiLCBpbnZlcnQgPSBUUlVFKQ0KDQpyZXMgPC0gDQogIGFuYWx5emVfb2JqZWN0c19zaHAoc3RhbmQsDQogICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSAiTkdSREkiLA0KICAgICAgICAgICAgICAgICAgICAgIGludmVydCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDcsDQogICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEpDQoNCnBhcihtZnJvdyA9IGMoMSwgMikpDQojIGNvYmVydHVyYSBkZSBzb2xvDQpwbG90X2luZGV4X3NocChyZXMpDQoNCiMgbWFwZWFtZW50byBkYXMgcGxhbnRhcyAoZGlzdMOibmNpYXMgZSBDViglKSkNCm9iamVjdF9tYXJrKHJlcykNCm1hcHBlZCA8LSAgb2JqZWN0X21hcChyZXMpDQoNCiMgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkZW50cm8gZGEgbGluaGENCmJhcnBsb3QobWFwcGVkJGN2cykNCg0KcGFyKG1mcm93ID0gYygxLCAxKSkNCmBgYA0KDQoNCiMgRml0b3BhdG9tZXRyaWENCiMjIEl0ZXJhdGl2YQ0KYGBge3J9DQpmb2xoYSA8LSBpbWFnZV9wbGltYW4oInNldl9sZWFmLmpwZyIsIHBsb3QgPSBUUlVFKQ0KIyBtZWFzdXJlX2Rpc2Vhc2VfaXRlcihmb2xoYSwgdmlld2VyID0gIm1hcHZpZXciKQ0KDQpgYGANCg0KDQojIyBVc2FuZG8gcGFsZXRhcw0KYGBge3J9DQpmb2xoYSA8LSBpbWFnZV9pbXBvcnQoInNveWJlYW5fcnVzdC9zb3lfMS5qcGciLCBwbG90ID0gVFJVRSkNCnBhbHMgPC0gaW1hZ2VfaW1wb3J0KHBhdHRlcm4gPSAic29qYV8iLA0KICAgICAgICAgICAgICAgICAgICAgcGF0aCA9ICJzb3liZWFuX3J1c3QiLA0KICAgICAgICAgICAgICAgICAgICAgcGxvdCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICBuY29sID0gMykNCnNldiA8LSANCiAgbWVhc3VyZV9kaXNlYXNlKGZvbGhhLA0KICAgICAgICAgICAgICAgICAgaW1nX2hlYWx0aHkgPSBwYWxzJHNvamFfaC5wbmcsICAgICAjIHBhbGV0YSBwYXJhIGZvbGhhIHNhZGlhDQogICAgICAgICAgICAgICAgICBpbWdfc3ltcHRvbXMgPSBwYWxzJHNvamFfcy5wbmcsICAgICMgcGFsZXRhIHBhcmEgZm9saGEgZG9lbnRlDQogICAgICAgICAgICAgICAgICBpbWdfYmFja2dyb3VuZCA9IHBhbHMkc29qYV9iLnBuZykgICMgcGFsZXRhIHBhcmEgZnVuZG8NCnNldiRzZXZlcml0eQ0KDQpgYGANCg0KIyMgVXNhbmRvIMOtbmRpY2VzIGRlIGltYWdlbQ0KYGBge3J9DQojIMONbmRpY2UgcGFyYSBzZWdtZW50YXIgYSBmb2xoYSBkbyBmdW5kbywgZGVwb2lzIGEgZG9lbsOnYSBkYSBmb2xoYQ0KaW1hZ2Vfc2VnbWVudF9pdGVyKGZvbGhhLCANCiAgICAgICAgICAgICAgICAgICBpbmRleCA9IGMoIkIiLCAiTkdSREkiKSwNCiAgICAgICAgICAgICAgICAgICBuY29sID0gMykNCg0KIyBJTVBPUlRBTlRFOiB0aGVzaG9sZCB2YWkgYWx0ZXJhciBhIHNldmVyaWRhZGUNCnNldjIgPC0gDQogIG1lYXN1cmVfZGlzZWFzZShmb2xoYSwNCiAgICAgICAgICAgICAgICAgIGluZGV4X2xiID0gIkIiLCAgICAgICAgICAgICMgw61uZGljZSBwYXJhIHNlZ21lbnRhciBhIGZvbGhhIGRvIGZ1bmRvDQogICAgICAgICAgICAgICAgICBpbmRleF9kaCA9ICJOR1JESSIsICAgICAgICAjIMOtbmRpY2UgcGFyYSBzZWdtZW50YXIgZm9saGEgZG9lbnRlIGUgc2FkaWENCiAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IGMoIk90c3UiLCAwKSkgICMgdGhyZXNob2xkIHBhcmEgb3MgZG9pcyDDrW5kaWNlcywgcmVzcGVjdGl2YW1lbnRlDQpzZXYyJHNldmVyaXR5DQoNCiMgZW0gbG90ZSAodXRpbGl6YW5kbyBhcyBwYWxldGFzKQ0Kc2V2MyA8LSANCiAgbWVhc3VyZV9kaXNlYXNlKHBhdHRlcm4gPSAic295XyIsDQogICAgICAgICAgICAgICAgICBkaXJfb3JpZ2luYWwgPSAic295YmVhbl9ydXN0IiwgICAgIyBwYXN0YSBjb20gYXMgaW1hZ2VucyBvcmlnaW5haXMNCiAgICAgICAgICAgICAgICAgIGRpcl9wcm9jZXNzZWQgPSAicHJvY19ydXN0IiwgICAgICAjIHBhc3RhIGNvbSBhcyBpbWFnZW5zIHByb2Nlc3NhZGFzDQogICAgICAgICAgICAgICAgICBzYXZlX2ltYWdlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIHBsb3QgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgIGltZ19oZWFsdGh5ID0gcGFscyRzb2phX2gucG5nLA0KICAgICAgICAgICAgICAgICAgaW1nX3N5bXB0b21zID0gcGFscyRzb2phX3MucG5nLA0KICAgICAgICAgICAgICAgICAgaW1nX2JhY2tncm91bmQgPSBwYWxzJHNvamFfYi5wbmcsDQogICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFRSVUUpDQojIHN0YW5kYXJkIGFyZWEgZGlhZ3JhbXMNCnNhZChzZXYzLCBuID0gNikNCg0Kc2V2NCA8LSANCiAgbWVhc3VyZV9kaXNlYXNlKHBhdHRlcm4gPSAic295XyIsDQogICAgICAgICAgICAgICAgICBkaXJfb3JpZ2luYWwgPSAic295YmVhbl9ydXN0IiwNCiAgICAgICAgICAgICAgICAgIHBsb3QgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgIGluZGV4X2xiID0gIkIiLA0KICAgICAgICAgICAgICAgICAgaW5kZXhfZGggPSAiTkdSREkiLA0KICAgICAgICAgICAgICAgICAgdGhyZXNob2xkID0gYygiT3RzdSIsIDApLA0KICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUUlVFKQ0KDQpwbG90KHNldjMkc2V2ZXJpdHkkc3ltcHRvbWF0aWMsIHNldjQkc2V2ZXJpdHkkc3ltcHRvbWF0aWMpDQoNCg0KYGBgDQoNCiMjIEVtIGdyaWRzDQoNCmBgYHtyfQ0KZm9saGFfZ3JpZCA8LSBpbWFnZV9pbXBvcnQoImRpc2Vhc2Vfc2hwLmpwZyIsIHBsb3QgPSBUUlVFKQ0Kc2V2NSA8LSANCiAgbWVhc3VyZV9kaXNlYXNlX3NocChmb2xoYV9ncmlkLA0KICAgICAgICAgICAgICAgICAgICAgIGluZGV4X2xiID0gIkhVRTIiLA0KICAgICAgICAgICAgICAgICAgICAgIGluZGV4X2RoID0gIk5HUkRJIiwNCiAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSBjKCJPdHN1IiwgMCksDQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gMTAsDQogICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgcGxvdCA9IEZBTFNFKQ0KcGxvdChmb2xoYV9ncmlkKQ0KcGxvdChzZXY1JHNoYXBlZmlsZXMpDQpwbG90X21lYXN1cmVzKHNldjUsICJzeW1wdG9tYXRpYyIpDQoNCmBgYA0KDQoNCg==